\chapter{Онтологія Metaweb}
Metaweb Technologies, Inc. - американська компанія з Сан-Франциско яка розробила Freebase. Заснована Денні Хіллісом в липні 2005, і працювала в невидимому режимі до 2007. Metaweb був придбаний компанією Google в липні, 2010\cite{mwgoogle}.

В даному розділі ми розглянемо їх продукт - базу даних всього на світі - Freebase. Це нереляційна база даних, хоча дані в ній досить гарно структуровані, що дозволяє зручно виконувати досить складні запити. На даний момент в базі міститься інформація про сотні тисяч об'єктів, яка перебуває в громадському надбанні.

Велика частина цієї інформації отримана завдяки вікіпедії. Структуровані дампи вікіпедії Metaweb поширює під вікіпедійною ліцензією GNU FDL v1.2, в рамках проекту Freebase Wikipedia Extraction\cite{WEX}.

\section{Hello, Freebase!}
Щоб одразу перейти до фізичної взаємодії:

Качаємо останню версію \verb!freebase-python!\cite{freebasepython}. Розпаковуємо архів, переходимо в нього і пишемо:
\begin{lstlisting}
sudo python setup.py build
sudo python setup.py install
\end{lstlisting}

Після цього пробуємо виконати простенький запит, наприклад дізнатись хто режисер фільму “Hot Fuzz”:
\begin{lstlisting}
import freebase
print freebase.mqlread({"name":"Hot Fuzz","type":"/film/film","directed_by":[]})
\end{lstlisting}

Словник що передається у функцію – запит MQL. Запити MQL записуються в форматі JSON, і всі поля що містять значення “[]“, або “null” заповнюються даними з бази. Детальна інструкція по MQL слідує:

\section{Архітектура Freebase}
Тепер трохи відійдемо від практики, і розглянемо структуру бази даних.

База даних Metaweb відрізняється від звичайних реляційних БД. Вона являє собою граф з вузлів та відношень. Також є додаткова частина – сховище медіа (content store). Вона призначена для зберігання бінарних файлів (BLOB в SQL), кожному з яких відповідає вузол графа. Ключем до файлу є його SHA2 хеш, це забезпечує відсутність дублікатів\cite{MQLRef}.

\subsection{Вузли та зв’язки}
На найнижчому рівні база даних Metaweb – це граф вузлів та зв’язків між ними. Кожен вузол має унікальний ідентифікатор та запис про те коли, й ким він був створений. Окрім ідентифікатора дати та автора вузли не містять жодної інформації. Все найцікавіше зберігається в зв’язках між вузлами (чи між вузлами та примітивами).

Зв’язки – це кортежі з 4 елементів (насправді 6, зв’язок теж має автора та час створення). Перший елемент From – перший (лівий) вузол зв’язку. Другий – Property – тип зв’язку. Наступне значення – To другий (правий) вузол зв’язку. Value – значення. Вузол може перебувати у відношенні з іншим вузлом, або зі значенням, або з обома одночасно, залежно від типу (Property) зв’язку.

Наприклад (TODO: Таблиця виходить за межі сторінки. Виправити):

\begin{tabular}{| l | l | l | l |}
\hline
From 	& Property &	To &	Value \\ 
\hline
\verb!/en/the_police! 	& \verb!/type/object/name! & 	\verb!/lang/en! &	\verb!The Police! \\
\verb!/en/zenyatta_mondatta! &	\verb!/type/object/name! &	\verb!/lang/en! &	\verb!Zenyatta Mondatta! \\
\verb!/en/zenyatta_mondatta! &	\verb!/music/album/artist! &	\verb!/en/the_police! &  \\
\hline	
\end{tabular}

Перший рядок каже, що вузол \verb!/en/the_police!, пов’язаний зв’язком \verb!/type/object/name! (ім’я) з вузлом \verb!/lang/en! (англійська мова) та значенням “The Police”, тобто англійською мовою вузол \verb!/en/the_police! називається “The Police”. Другий дає подібну інформацію про альбом “Zenyatta Mondatta”. Третій – каже про те, що альбом та група пов’язані через \verb!/music/album/artist!, тобто “Zenyatta Mondatta” – альбом групи “The Police”.

\subsection{Властивості}

Властивості об’єктів (вузлів) в БД задаються типами зв’язків. Можна було помітити що колонка Property попередній таблиці містить ідентифікатори подібні до ідентифікаторів вузлів. А все тому, що тип зв’язку теж є вузлом, і його теж можуть створити користувачі, і він теж може попадати в поля From та To. Наприклад:

\begin{tabular}{| l | l | l | l |}
\hline
From &	Property &	To &	Value \\
\hline
\verb!/type/object/name! &	\verb!/type/object/name! &	\verb!/lang/en! &	\verb!Name! \\
\verb!/music/album/artist! & 	\verb!/type/object/name! &	\verb!/lang/en! &	\verb!Artist! \\
\verb!/music/track/album! &	\verb!/type/object/name! &	\verb!/lang/en! &	\verb!Appears On! \\
\verb!/music/album/artist! &	\verb!/type/property/unique! &	 &	\verb!true! \\
\verb!/music/track/album! &	\verb!/type/property/unique! & &	\verb!false! \\
\hline
\end{tabular}

Перший рядок цієї таблиці має доволі цікавий сенс. Він каже нам про те, що ім’я властивості ім’я англійською мовою “Name”.

\subsection{Напрямки властивостей}
Напевне досить очевидно, що граф бази даних – напрямлений, так як для зв’язку конкретно вказано куди і звідки. Але Metaweb вміє переміщуватись по графу в обидві сторони.

Наприклад розглянемо зв’язок між альбомами та треками. Кожна композиція (трек) має властивість “альбом[и]” в яких вона була видана. Ми можемо здійснити запит “дізнатись в яких альбомах публікувалась Driven to Tears”, і Metaweb знайде всі значення поля “To” кортежів, в яких поле “From” містить “Driven to Tears”, а поле “Property” – \verb!/music/track/album!. Можна задати протилежний запит – “які треки містить альбом Zenyatta Mondatta?”. Metaweb дасть нам значення поля “From” всіх кортежів які містять “Zenyatta Mondatta” в полі “To”, та \verb!/music/track/album! в “Property”.

Metabase має як властивість альбоми в яких видавалась композиція (\verb!/music/track/album!), так і протилежну – композиції альбому. (\verb!/music/album/track!). Такі властивості називаються взаємними (англ. reciprocal properties), і такий їх зв’язок теж описується в графі:

\begin{tabular}{| l | l | l | l |}
\hline
From &	Property &	To &	Value \\
\hline
\verb!/music/track/album ! & \verb!/type/property/reverse_property! & \verb!/music/album/track! \\
\hline
\end{tabular}

\subsection{Значення властивостей}
Деякі властивості є базовими, тобто вбудовані в архітектуру і мають чітко прописане значення. Наприклад на \verb!/type/object/name! накладається обмеження, що кожен об’єкт хоча й може мати багато імен, але лише одне кожною мовою. Іншою властивістю вбудованою в архітектуру є наприклад \verb!/type/property/unique!, яка показує чи властивість вказує на один об’єкт, чи на множину.

Щоправда більшість властивостей не такі. \verb!/music/album/artist! не є частиною архітектури. Його створили користувачі freebase.com для запису інформації про музику. Сам ідентифікатор властивості дає нам підказку про те що вона означає, яка підтверджується тим, що ця властивість має ім’я “Artist” (через зв’язок \verb!/type/object/name!). Ми навіть можемо отримати коротку інструкцію використання властивості, якщо використаємо властивість \verb!/freebase/documented_object/tip!.

Таким чином значення \verb!/type/property/unique! закодоване прямо в реалізації БД, а значення \verb!/music/album/artist! існує тільки в головах користувачів.

\subsection{Назви, ідентифікатори та простори імен}

Кожен вузол має унікальний ідентифікатор, але не зобов’язаний мати унікальне ім’я. Вузли \verb!/lang/en!, \verb!/en/english_people!, та \verb!/authority/gnis/57724! відповідають мові, нації, та місту в штаті Акранзас, і всі мають однакову назву англійською – “English”. А якщо є два вузли що мають однакові ідентифікатори – то це один і той самий вузол. Ідентифікатори не є незмінними, їх можна редагувати як і вузли. Можна змінити ідентифікатор вузла, і можна зробити так щоб ідентифікатор показував на інший вузол.

Такий ідентифікатор як наприклад \verb!/type/object/name! складається з двох частин – \verb!/type/object!, яка називається простором імен (і в свою чергу теж є ідентифікатором з простору імен \verb!/type!), та name – який називається ключем. Це трохи нагадує структуру директорій Unix.

Ідентифікатори на зразок \verb!/en/the_police! написані майже англійською мовою, тому досить зрозумілі. Щоправда такі ідентифікатори вдається надати не всім вузлам, тому окрім них, кожен вузол ідентифікується ключами з простору імен guid (англ. globally-unique identifier), наприклад пісня “Driven to Tears” має ідентифікатор \verb!/guid/9202a8c04000641f800000000129a87a!. На рівні реалізації БД, зв’язки між вузлами встановлюються записом в поля кортежу From, To та Property саме цих ідентифікаторів, а не тих, що були показані в таблицях. guid – фундаментальна властивість кожного вузла, на відміну від інших ідентифікаторів. Ці інші ідентифікатори можна отримати через зв’язки типу \verb!/type/object/key! де в полі “To” дається простір імен, а в “Value” – ключ. Простір імен теж вузол, тому теж має ідентифікатор.

\subsection{Об’єкти та типи}
Дотепер ми казали що база даних складається з вузлів та зв’язків, і старанно уникали слова “об’єкт” (можете перевірити). Але воно зустрічалось в таких ідентифікаторах як наприклад \verb!/type/object/key!, чи \verb!/freebase/documented_object/tip!. Тому, хоча дуже потрібно знати що на найнижчому рівні Freebase складається з кортежів що задають зв’язки між вузлами, але варто поглянути на неї через об’єктно-орієнтовані окуляри O\^O.

Тому замість того щоб думати про зв’язки між вузлами пов’язаними з вузлом групи “The Police” дані можна представити таким псевдокодом:

\begin{lstlisting}
{
  id: "/en/the_police",
  name: "The Police",
  /music/artist/album: {
    id: "/en/zenyatta_mondatta",
    name: "Zenyatta Mondatta",
    /music/album/track: {
      name: "Driven to Tears",
      /music/track/length: 200.266
    }
    /music/album/track: {
      name: "Canary in a Coalmine",
      /music/track/length: 146.506
    }
  }
}
\end{lstlisting}

Нагадує JSON, правда? Це не випадково. Ми бачимо об’єкт, де \verb!id = /en/the_police! та \verb!name = "The Police"!. \verb!id! та \verb!name! – скорочення що відповідають універсальним властивостям \verb!/type/object/id! та \verb!/type/object/name!, які доступні всім об’єктам. Всередині нього є об’єкт що відповідає альбому, а всередині альбому – об’єкти для треків (загалом їх більше, але вони були опущені для лаконічності). Відомості про альбоми та треки покладаються на властивості \verb!/music/artist/album! та \verb!/music/album/track!.

Щоб завершити огляд Freebase з об’єктно-орієнтованого погляду потрібно розповісти про типи. Типи – це колекції однотипних властивостей, і об’єкт в Metaweb може бути екземпляром одного чи кількох типів. \verb!/en/the_police! – екземпляр типу \verb!/music/artist!, \verb!/en/zenyatta_mondatta! – екземпляр типу \verb!/music/album!, і об’єкт що представляє трек є екземпляром \verb!/music/track!. Типи, як і властивості інше представлені вузлами. Властивості є екземплярами типу \verb!/type/property!, а кожен тип – екземпляр \verb!/type/type! (що означає що \verb!/type/type! – екземпляр самого себе!) Об’єкти що мають властивості використовують свої ідентифікатори в якості простору імен для ідентифікаторів типів цих властивостей. Не переживайте якщо не зрозуміли попереднє речення, я й сам його ледве зрозумів. Поясню на прикладах. Властивості \verb!/music/track!, такі як \verb!/music/track/album! чи \verb!/music/track/length!, мають ідентифікатори що починаються з \verb!/music/track!.

Типи та властивості пов’язані унікальною властивістю \verb!/type/property/schema!, яка описує зв’язок між властивістю, та типом до якого ця властивість входить. Зворотня властивість \verb!/type/type/properties! дає всі властивості типу.

Існує ще дві, важливіші властивості що включають типи. Це \verb!/type/object/type!, що аналогічно до \verb!/type/object/name! використовується практично для кожного об’єкта в базі. Задає всі типи, екземплярами яких є об’єкт. Наприклад \verb!/en/the_police! є екземляром \verb!/music/artist!, \verb!/common/topic!, \verb!/music/producer!, та \verb!/music/musical_group!.

Знати тип потрібно з двох причин: якщо ми знаємо що об’єкт – це \verb!/music/artist!, ми знаємо що є сенс запитати про значення його властивості \verb!/music/artist/album!. І тип об’єкта – чудовий уточнювач. Ми можемо знайти багацько об’єктів що називаються “English”, але можемо суттєво звузити пошук, якщо скажемо що нас цікавлять лише екземпляри \verb!/type/lang!.

На додачу до \verb!/type/object/type! є ще одна властивість пов’язана з типами. Це унікальна властивість \verb!/type/property/expected_type! (очікуваний тип), що для кожної властивості задає тип значення пов’язаного з цією властивістю. Наприклад очікуваним типом властивості \verb!/music/artist/album! є \verb!/music/album!, а очікуваним типом \verb!/music/album/track! є \verb!/music/track!.

Додавання типу об’єкта дозволяє нам суттєво спростити його запис:
\begin{lstlisting}
{
  id: "/en/the_police",
  type: "/music/artist",
  name: "The Police",
  album: {
    id: "/en/zenyatta_mondatta",
    name: "Zenyatta Mondatta",
    track: {
      name: "Driven to Tears",
      length: 200.266
    }
    track: {
      name: "Canary in a Coalmine",
      length: 146.506
    }
  }
}
\end{lstlisting}

Ми додали в зовнішній об’єкт властивість type, який задав тип \verb!/music/artics!. Це дозволяє нам використати просте ім’я властивості замість \verb!/music/artist/album!. Більше того, так як ми знаємо що очікуваним типом для \verb!/music/artist/album! є \verb!/music/album!, ми можемо простом використати ім’я властивості track замість \verb!/music/album/track!. Аналогічно \verb!/music/track/length! скорочується до \verb!length!.

\section{Metaweb Query Language}
Для зручності дослідження Freebase, та вивчення мови запитів, розробники створили “Query Editor”\cite{queryeditor} – зручний інструмент що працює прямо в браузері, та має підказки з автодоповненням та інші зручності.

Як вже згадувалось вище, MQL базується на JSON, тобто структура даних аналогічна до тієї яку ми можемо створити з словників, масивів та базових типів (рядків та чисел) Python. Відмінність між JSON та Python покажемо в таблиці:

\begin{tabular}{| l | l | l |}
\hline
Python 	& JSON 	& Значення \\
\hline
\verb!None! 	& \verb!null! 	& Немає даних \\
\verb!False! 	& \verb!false! &  \\	
\verb!True! 	& \verb!true! 	& \\
\verb!'"'! 	& \verb!"\""! 	& Рядки в JSON – тільки в подвійних лапках \\
\hline
\end{tabular}

На цьому здається все. Відмінностей від Python не так і багато.

Спробуємо написати простий запит, який наприклад нам дасть список властивостей, які характеризують тип \verb!/film/film!:

\begin{lstlisting}
[{
  "id": "/film/film",
  "type": "/type/type",
  "properties": []
}]
\end{lstlisting}

В результаті виконання запиту, в правому полі (якщо ви писали запит в Query Editor) буде приблизно такий текст:


\begin{lstlisting}
{
  "code":          "/api/status/ok",
  "result": [{
    "id":   "/film/film",
    "properties": [
      "/film/film/initial_release_date",
      "/film/film/directed_by",
      далі багато властивостей пропущено для компактності
    ],
    "type": "/type/type"
  }],
  "status":        "200 OK",
  "transaction_id": "cache;cache03.p01.sjc1:8101;2011-04-02T19:19:20Z;0041"
}
\end{lstlisting}

Як вже було сказано, відповідь на запит – це цей же запит, з заповненими полями, які мали значення \verb![]! чи \verb!null!. Цю відповідь ми можемо бачити в полі “result” відповіді. Окрім “result” є інші поля з службовою інформацією.

А тепер спробуємо написати в нашому запиті замість \verb![] null!. Тобто так:
\begin{lstlisting}
[{
  "id": "/film/film",
  "type": "/type/type",
  "properties": []
}]
\end{lstlisting}

Відповідь сервера зміниться. Він повідомить нас про помилку:

\begin{lstlisting}
{
  "code":          "/api/status/error",
  "messages": [{
    "code":    "/api/status/error/mql/result",
    "info": {
      "count": 52,
      "result": [
        "/film/film/initial_release_date",
        "/film/film/directed_by",
        знову багато пропущено...
      ]
    },
    "message": "Unique query may have at most one result. Got 52",
    "path":    "properties",
    "query": [{
      "error_inside": "properties",
      "id":           "/film/film",
      "properties":   null,
      "type":         "/type/type"
    }]
  }],
  "status":        "200 OK",
  "transaction_id": "cache;cache03.p01.sjc1:8101;2011-04-02T19:25:14Z;0013"
}
\end{lstlisting}

Суть помилки пояснюють в полі “\verb!message!”: написавши в полі \verb!null! ми очікуємо що база даних заповнить його значенням, але база даних знайшла їх аж 52 штуки. Простим вирішенням помилки є повернення до попередньої версії запиту, коли ми просили базу даних заповнити список.

Тут варто зауважити що навіть об’єкт може мати навіть кілька типів, тому наприклад запит
\begin{lstlisting}
[{ "id": "/film/film", "type":null }]
\end{lstlisting}

теж дасть аналогічну помилку. З іншого боку, якщо навіть властивість може мати лише одне значення (як наприклад \verb!id!), ми все одно можемо запитати не через \verb!null!, а через \verb![]!. Тоді потрібне нам значення потрапить в перший елемент списку.

\chapter{Використання Freebase в контексті даної роботи}
Роботи в вікіпедії працюють за принципом IPO (input processing output). Найскладнішою частиною звісно є processing, бо йде мова про обробку природньої мови, яка може містити що завгодно. Проте, якщо замінити ввід з вікіпедії на ввід з Freebase - ситуація докорінно зміниться. Це можна використати на свою користь багатьма різними способами.

\section{Словник транслітерації імен}
Задача: пройтись по інтервікісловнику, вияснити які статті пишуть про людей, тобто мають заголовки виду “Прізвище Ім’я”, розділити ці заголовки на дві частини, і таким чином можливо трохи скоротити словник. За одно отримати словник транслітерацій імен і прізвищ.

Для цього:
\begin{enumerate}
    \item За назвою статті шукаємо об’єкт в Freebase який з нею пов’язаний.
    \item Шукаємо типи цього об’єкта. Якщо він має тип \verb!/peoples/person!, значить це людина (правда на жаль тільки реально існуюча, тому якогось там Індіану Джонса доведеться вводити вручну). Та все одно це простіше.
    \item Якщо це не людина виходимо.
    \item Розбиваємо назви на слова.
    \item Дивимось кількість слів в англійському та українському написанні. Якщо вона різна – виходимо.
    \item Питаємо користувача чи не переплутаний порядок слів. Якщо переплутаний – виходимо.
    \item Дивимось чи немає вже таких транслітерацій в словнику. Якщо є – питаємо користувача яка краща.
\end{enumerate}

Функція перевірки на “людськість”:
\begin{lstlisting}
personquery = {
        "key":[{"namespace":"/wikipedia/en", "value":None}],
        "type":[]
}

def is_person(article_name):
        if article_name.find(":")!=-1:
                return False
        personquery["key"][0]["value"]=upper1(article_name.replace(" ","_") )
        # Not shure that this is real transformation name -> link
        try:
                res = freebase.mqlread(personquery)
        except MetawebError:
                return False
        if res:
                return "/people/person" in res["type"]
        else:
                return False
\end{lstlisting}

Що таке \verb!"namespace":"/wikipedia/en"! можна прочитати в \cite{nsandkeys}.

\begin{verbatim}
>>> is_person("Linus Thorvalds")
False
>>> is_person("Linus Torvalds")
True
>>> is_person("Indiana Jones")
False
>>> is_person("Banksy")
True
>>> is_person("Bunyk Taras")
False
\end{verbatim}

Звісно останній результат мене дещо засмучує :), але при складанні словника помилки типу false negative не призводять до жодних помилок в ньому. Хіба що він буде дещо неповним, але він за самим означенням вікіпедії завжди буде неповним.

Гірше те, що я щойно виявив false positive. Наприклад хтось дав в Freebase буддизму тип \verb!/people/person!. Хоча до такого варто бути готовим, коли працюємо з інформацією яку створюють люди.

Проблема в тому, що запити до віддаленої бази даних – це найвузькіше місце в програмі. За 124 секунди робиться трохи більше 150 запитів, відповідно щоб зробити 150 000 запитів треба в тисячу разів більше секунд. Програма запускалась двічі, і один раз на цілу ніч. Зате тепер маю список, в якому з великою ймовірністю імена людей (upd: і в ньому якісь проблеми з ключами :( ).

\section{Стаби кінофільмів}
Стаб (англ. stub, фр. eboche) — коротка, але інформативна стаття у Вікіпедії, яка має перспективу для розширення.

Український аналог терміну стаб станом на кінець 2008 року ще не вироблений. Можна запропонувати терміни «заготовка статті», «засічка під статтю», стаття-заготовка тощо.

Для того, щоб вказати що стаття є стабом ставиться шаблон \verb!{{stub}}! , або відповідний галузевий шаблон.

Інформацію про кінофільм можна отримати за допомогою запиту:

\begin{lstlisting}
	query = [{
		'type':'/film/film',
		'name':name, #Hot Fuzz',
		'id':None,
		'directed_by':[],
		'produced_by':[],
		'starring':[{'actor':None, 'character':None, 'character_note':None}],
		'language':[],
		'genre':[],
		'initial_release_date':None,
		'written_by':[],
		'music':[],
		'cinematography':[],
		'edited_by':[],
		'rating':[],
		'production_companies':[],
		'distributors':[],
		'sequel':None,
		'prequel':None,
		'runtime':[{'runtime':None}],
		'country':[],
		'estimated_budget':[{'amount':None, 'currency':None, 'optional':True}],
		'gross_revenue':[{'amount':None, 'currency':None,'optional':True}],
		'rottentomatoes_id':None,
		'key':[{'namespace':None,'value':None}],
	}]
\end{lstlisting}

Потім всі дані проганяються через функції перекладу. Переклад проходить в основному інтервікі-словник, проте завдяки тому що інформація додатково структурована та має чітку семантику, функції для перекладу можуть бути більш спеціалізованими. Наприклад переклад дати в форматі ISO 8601 на українську:

\begin{verbatim}
def iso8601(d):
	""" From iso8601 to Ukrainian """
	l= d.split('-')
	if len(l)<2:
		return l[0]
	months = {
		"01":u'січня',
		"02":u'лютого',
		"03":u'березня',
		"04":u'квітня',
		"05":u'травня',
		"06":u'червня',
		"07":u'липня',
		"08":u'серпня',
		"09":u'вересня',
		"10":u'жовтня',
		"11":u'листопада',
		"12":u'грудня'
	}

	return l[2]+u' '+months[l[1]]+u' '+l[0]
\end{verbatim}

Після цього отримані дані підставляються в готовий шаблон, аналогічно до того, як це роблять в веб-програмуванні:
\begin{verbatim}
'''%(ukname)s''' ({{lang-en|%(enname)s}}) - фільм

== Сюжет ==
{{section-stub}}

== В ролях ==
%(cast)s

== Посилання ==
* Використано матеріали з бази даних [http://www.freebase.com/view%(freebaseid)s Freebase].
* {{Imdb title|%(imdbid)s|%(enname)s}}
* {{rotten-tomatoes|id=%(tomatoesid)s|title=%(enname)s}}
* {{metacritic film|%(metacriticid)s}}

{{film-stub}}

[[en:%(enname)s]]
\end{verbatim}

Повний код цього скрипта знаходиться в файлі \verb!film_stubber.py! \cite{code}. Приклад роботи - на зображенні \ref{filmstub}.

\begin{figure}[!h]
\includegraphics[width=1.0\textwidth]{film-stub.png} 
\centering \caption{Приклад статті-стабу} \label{filmstub}
\end{figure}
